package edu.ccut.saturn.component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import edu.ccut.saturn.component.impl.SaturnMenuInfo;

/**
 * 提供了单态实例维护加载的菜单项配置文件信息。支持多种获得菜单项配置信息的方法。
 * <p><li>字段defaultMenuInfos：记录了每个bundle中的默认的菜单配置文件的信息；
 * <li>字段menuInfos：记录了运行时的所有菜单配置文件的信息；在运行时阶段可以修改菜单的显示顺序，并把修改的信息保存到数据库中。通过查询数据库的配置信息表获得修改过的菜单信息。
 * <li>字段allmemuItems：记录了所有的菜单项的信息。
 * 
 * @author 谷鈺
 * @author 温建
 * 
 * @version 1.0 2008.9.04
 * 
 * @see IMenuInfo
 * @see IMuneItemInfo
 * 
 */
public class SaturnMenuManager {

	private static final String LOGGER_KEY_BUNDLE_SERVICE = SaturnLoggerManager.LOGGER_KEY_BUNDLE_SERVICE;

	private static final String MENU_QUERY_SQL = "select id, value, symbolicName from saturnconfig where type = 'menu'";

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(LOGGER_KEY_BUNDLE_SERVICE);

	private static SaturnMenuManager instance;

	private Map<String, IMenuInfo> defaultMenuInfos;

	private Map<String, IMenuInfo> menuInfos;

	private List<IMuneItemInfo> allmemuItems;

	static {
		instance = new SaturnMenuManager();
	}

	private SaturnMenuManager() {
		this.defaultMenuInfos = new HashMap<String, IMenuInfo>();
		this.menuInfos = new HashMap<String, IMenuInfo>();
		this.allmemuItems = new ArrayList<IMuneItemInfo>();
	}

	/**
	 * 获得单态实例
	 * @return
	 */
	public static SaturnMenuManager getInstance() {
		return instance;
	}

	/**
	 * 加载bundle中的菜单信息。首先获得bundle中的配置文件中记录的信息并保存到defaultMenuInfos中；
	 * 然后把默认信息拷贝到menuInfos中；再查询数据库根据数据库中记录的信息和默认的菜单信息相比较，
	 * 以数据库中的信息更新菜单的显示顺序，并保存到menuInfos中。
	 * 
	 * @param bundleInfo
	 */
	public void addBundleMenuInfo(IBundleInfo bundleInfo) {
		this.defaultMenuInfos.put(bundleInfo.getBundleSymbolicName(),
				bundleInfo.getBundleMenuInfo());

		addMenuInfos(bundleInfo);
		getMenuOrdersFromDatabase(bundleInfo);
		logger.debug("add bundleMenuInfo key \""
				+ bundleInfo.getBundleSymbolicName() + "\"");
	}
	
	/**
	 * 将bundle中的菜单信息保存到menuInfos中。
	 * @param bundleInfo
	 */
	public void addMenuInfos(IBundleInfo bundleInfo) {
		SaturnMenuInfo saturnMenuInfo = new SaturnMenuInfo(bundleInfo
				.getBundleMenuInfo());

		this.menuInfos.put(bundleInfo.getBundleSymbolicName(), saturnMenuInfo);
	}

	/**
	 * 将菜单项信息保存到allmemuItems中
	 * @param itemInfo
	 */
	public void addMenuInfosList(IMuneItemInfo itemInfo) {
		this.allmemuItems.add(itemInfo);
	}

	/**
	 * 按照数据库中的菜单信息更新保存的菜单项的显示顺序。
	 * @param bundleInfo
	 */
	public void getMenuOrdersFromDatabase(IBundleInfo bundleInfo) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet rs = null;

		try {
			connection = DatabaseManager.getInstance().getConnection();

			if (connection != null) {
				preparedStatement = connection.prepareStatement(MENU_QUERY_SQL);
				rs = preparedStatement.executeQuery();

				while (rs.next()) {

					if (bundleInfo.getBundleSymbolicName().equals(
							rs.getString("symbolicName"))) {

						IMenuInfo menuInfo = menuInfos.get(rs.getString("symbolicName"));
						List<IMuneItemInfo> itemInfoList = menuInfo
								.getMenuItemInfos();

						if (itemInfoList.size() > 0) {

							for (IMuneItemInfo itemInfo : itemInfoList) {

								if (itemInfo.getId().equals(rs.getString("id"))) {
									itemInfo.setOrder(rs.getString("value"));
									itemInfo.setMenuInfo(menuInfo);
									break;
								}
							}
						}
					}
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();

		} finally {

			try {

				if (preparedStatement != null) {
					preparedStatement.close();
				}

				if (rs != null) {
					rs.close();
				}

				if (connection != null) {
					connection.close();
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 删除指定的bundle
	 * @param symbolicName
	 */
	public void removeBundleMenuInfo(String symbolicName) {
		List<IMuneItemInfo> removeItemList = new ArrayList<IMuneItemInfo>();
		if (allmemuItems != null) {
			for (IMuneItemInfo item : allmemuItems) {
				if (item.getId().startsWith(symbolicName)) {
					removeItemList.add(item);
				}
			}
		}
		if (removeItemList.size() > 0) {
			allmemuItems.removeAll(removeItemList);
		}
		if (menuInfos.containsKey(symbolicName)) {
			this.menuInfos.remove(symbolicName);
			logger.debug("remove bundleMenuInfo key is : \"" + symbolicName
					+ "\"");

			return;
		}
		logger
				.warn("failed to remove bundleMenuInfoInfo, because the bundle key : \""
						+ symbolicName + "\" is not valid");
	}

	/**
	 * 
	 * @param symbolicName
	 * @return
	 * @throws SaturnComponentException
	 */
	public IMenuInfo getMenuInfo(String symbolicName)
			throws SaturnComponentException {

		IMenuInfo menuInfo = this.menuInfos.get(symbolicName);

		if (menuInfo == null) {
			throw new SaturnComponentException(
					"Failed to get menu config file ;can't find bundle with symbolicName = ["
							+ symbolicName + "] ");
		}
		return menuInfo;
	}

	/**
	 * 
	 * @return
	 */
	public Collection<IMenuInfo> getAllMenuInfos() {
		return this.menuInfos.values();
	}

	/**
	 * 
	 * @return
	 */
	public List<Map<String, String>> getMenuInfosByMap() {

		List<Map<String, String>> menus = new LinkedList<Map<String, String>>();
		Collection<IMenuInfo> menuInfoList = getAllMenuInfos();
		List<IMuneItemInfo> allMenuItemInfo = new ArrayList<IMuneItemInfo>();

		for (IMenuInfo menuInfo : menuInfoList) {

			if (menuInfo != null) {
				List<IMuneItemInfo> menuItemInfos = menuInfo
						.getRootMenuItemInfos();

				if (menuItemInfos != null) {
					allMenuItemInfo.addAll(menuItemInfos);
				}
			}
		}
		Collections.sort(allMenuItemInfo);
		filterSameOrderItemOfList(allMenuItemInfo);

		if (allMenuItemInfo != null && !allMenuItemInfo.isEmpty()) {
			LinkedList<IMuneItemInfo> nodes = new LinkedList<IMuneItemInfo>();
			nodes.addAll(allMenuItemInfo);

			while (!nodes.isEmpty()) {
				IMuneItemInfo node = nodes.removeFirst();
				Map<String, String> treeNode = new HashMap<String, String>();
				treeNode.put("id", node.getId());

				if (node.getParentId() == null || "".equals(node.getParentId())) {
					treeNode.put("parentId", "");
				} else {
					String parentId = node.getParentId();
					treeNode.put("parentId", parentId);
				}
				treeNode.put("label", node.getLabel());
				// treeNode.put("icon", "/server-main/images/003.gif");
				// treeNode.put("expandedIcon",
				// "/server-main/images/012.gif");
				treeNode.put("path", this.getNodePath(node));
				menus.add(treeNode);
				List<IMuneItemInfo> children = getMenuItemsOfRootMenuItem(node
						.getId());

				if (!children.isEmpty()) {
					Collections.sort(children);
					filterSameOrderItemOfList(children);
					nodes.addAll(children);
				}
			}
		}
		return menus;
	}

	/**
	 * 
	 * @param userSerialno
	 * @param userType
	 * @return
	 */
	/*public List<Map<String, String>> getMenuInfosByMap(String userSerialno,
			String userType) {

		List<Map<String, String>> menus = new LinkedList<Map<String, String>>();
		Collection<IMenuInfo> menuInfoList = getAllMenuInfos();
		List<IMuneItemInfo> allMenuItemInfo = new ArrayList<IMuneItemInfo>();

		for (IMenuInfo menuInfo : menuInfoList) {

			if (menuInfo != null) {
				List<IMuneItemInfo> menuItemInfos = menuInfo
						.getRootMenuItemInfos();

				if (menuItemInfos != null) {
					allMenuItemInfo.addAll(menuItemInfos);
				}
			}
		}
		Collections.sort(allMenuItemInfo);
		filterSameOrderItemOfList(allMenuItemInfo);
		if (allMenuItemInfo != null && !allMenuItemInfo.isEmpty()) {
			LinkedList<IMuneItemInfo> nodes = new LinkedList<IMuneItemInfo>();
			nodes.addAll(allMenuItemInfo);
			while (!nodes.isEmpty()) {
				IMuneItemInfo node = nodes.removeFirst();
				Map<String, String> treeNode = new HashMap<String, String>();
				treeNode.put("id", node.getId());
				if (node.getParentId() == null || "".equals(node.getParentId())) {
					treeNode.put("parentId", "");
				} else {
					String parentId = node.getParentId();
					treeNode.put("parentId", parentId);
				}
				treeNode.put("label", node.getLabel());
				treeNode.put("path", this.getNodePath(node));
				menus.add(treeNode);
				List<IMuneItemInfo> children = getMenuItemsOfRootMenuItem(node
						.getId());

				if (!children.isEmpty()) {
					Collections.sort(children);
					filterSameOrderItemOfList(children);
					nodes.addAll(children);
				}
			}
		}
		if (!userType.equals("00")) {
			filterMenuInfosMayByUserAuthority(userSerialno, menus);
		}
		return menus;
	}*/

	/**
	 * 
	 * @param userSerialno
	 * @param allNodesList
	 */
	@SuppressWarnings("unchecked")
	/*public void filterMenuInfosMayByUserAuthority(String userSerialno,
			List<Map<String, String>> allNodesList) {

		if (userSerialno != null && !userSerialno.equals("")) {
			List<Map<String, String>> leafNodeList = new ArrayList<Map<String, String>>();
			IParameterContext parameterContext = null;
			IComponent component = null;

			try {
				component = ComponentManager
						.getInstance()
						.getComponent(
								"edu.ccut.saturn.authority.impl::/loginModule/logic/GetUserResourceList.logic");

				parameterContext = ComponentFactory.createParameterContext();
				parameterContext.addParameter(userSerialno, String.class);
				parameterContext.addParameter(null, ArrayList.class);
				component.execute(parameterContext);
				List<SaturnData> userAuthList = (List<SaturnData>) parameterContext
						.getParameterValue(1);

				if (userAuthList != null) {

					for (Map<String, String> nodeInfo : allNodesList) {
						for (SaturnData userAuth : userAuthList) {
							String url = userAuth.getString("url");
							String path = nodeInfo.get("path");
							if (isResourceMapping(url, path)) {
								leafNodeList.add(nodeInfo);
							}
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				return;
			}
			List<Map<String, String>> allContainNodeList = new ArrayList<Map<String, String>>();
			List<Map<String, String>> allDelNodeList = new ArrayList<Map<String, String>>();
			getAllContainNodeList(leafNodeList, allContainNodeList,
					allNodesList);
			for (Map<String, String> nodeMapOfAll : allNodesList) {
				String id = nodeMapOfAll.get("id");
				int isContain = 0;
				for (Map<String, String> nodeMap : allContainNodeList) {
					if (nodeMap.get("id").equals(id)) {
						isContain = 1;
						break;
					}
				}
				if (isContain == 0) {
					allDelNodeList.add(nodeMapOfAll);
				}
			}
			for (Map<String, String> delNodeMap : allDelNodeList) {
				if (allNodesList.contains(delNodeMap)) {
					allNodesList.remove(delNodeMap);
				}
			}
		}
	}*/

	/**
	 * 
	 * @param leafNodeList
	 * @param allContainNodeList
	 * @param allNodesList
	 */
	public void getAllContainNodeList(List<Map<String, String>> leafNodeList,
			List<Map<String, String>> allContainNodeList,
			List<Map<String, String>> allNodesList) {

		if (leafNodeList != null) {
			allContainNodeList.addAll(leafNodeList);
			List<Map<String, String>> parentNodeList = new ArrayList<Map<String, String>>();
			for (Map<String, String> leafNode : leafNodeList) {
				getParentNodeList(leafNode, parentNodeList, allNodesList);
			}
			if (parentNodeList.size() > 0) {
				allContainNodeList.addAll(parentNodeList);
			}
		}

	}

	/**
	 * 
	 * 
	 * @param child
	 * @param parentNodeList
	 * @param allNodesList
	 */
	public void getParentNodeList(Map<String, String> child,
			List<Map<String, String>> parentNodeList,
			List<Map<String, String>> allNodesList) {

		for (Map<String, String> node : allNodesList) {
			if (!child.get("parentId").equals("")
					&& node.get("id").equals(child.get("parentId"))) {

				int isContain = 0;
				for (Map<String, String> parentNode : parentNodeList) {
					if (parentNode.get("id").equals(node.get("id"))) {
						isContain = 1;
						break;
					}
				}
				if (isContain == 0) {
					parentNodeList.add(node);
					getParentNodeList(node, parentNodeList, allNodesList);
				}
			}
		}
	}

	/**
	 * 对资源的匹配，首先匹配资源的路径信息，然后匹配资源名，支持通配符“*”
	 * @param url
	 * @param path
	 * @return
	 */
	public boolean isResourceMapping(String url, String path) {

		if (url == null || path == null || path.equals("")) {
			return false;
		}
		if (url.endsWith("/*")) {
			String urlPre = url.substring(0, url.indexOf("::"));
			if (path.indexOf(urlPre) != -1) {
				return true;
			}
		}
		if (url.equals(path)) {
			return true;
		}
		// if (url.indexOf("::") == -1 || path.indexOf("::") == -1) {
		// return url.equals(path);
		// }
		int urlSepIndex = url.lastIndexOf("/");
		int pathSepIndex = path.lastIndexOf("/");
		String urlName = url.substring(urlSepIndex + 1, url.length());
		String urlDic = url.substring(0, urlSepIndex);
		String pathName = path.substring(pathSepIndex + 1, path.length());
		String pathDic = path.substring(0, path.lastIndexOf("/"));
		if (url.indexOf("**") != -1) {
			String urlDicPre = urlDic.substring(0, urlDic.lastIndexOf("/"));
			// String pathDicPre = pathDic.substring(0,
			// pathDic.lastIndexOf("/"));
			String pathDicPre = pathDic.substring(0, pathDic.indexOf("/", 1));
			if (urlDicPre.equals(pathDicPre)) {
				return isResourceNameMapping(urlName, pathName);
			}
		} else {
			if (urlDic.equals(pathDic)) {
				return isResourceNameMapping(urlName, pathName);
			}
		}
		return false;
	}

	/**
	 * 匹配资源名称，可以有通配符“*”。
	 * 
	 * @param urlName 
	 * @param pathName 
	 * @return
	 */
	public boolean isResourceNameMapping(String urlName, String pathName) {

		if (urlName.equals("*.*")) {
			return true;
		} else {

			if (urlName.startsWith("*.")) {
				return urlName.substring(urlName.indexOf(".") + 1,
						urlName.length()).equals(
						pathName.substring(pathName.indexOf(".") + 1, pathName
								.length()));

			} else if (urlName.endsWith(".*")) {
				return urlName.substring(0, urlName.indexOf(".") + 1).equals(
						pathName.substring(0, pathName.indexOf(".") + 1));

			} else {
				return urlName.equals(pathName);
			}
		}
	}

	/**
	 * 从给定的结点信息中获得指定的根菜单的子菜单信息
	 * 
	 * @param rootNodeMap
	 * @param allNodeList
	 * @return
	 */
	public List<Map<String, String>> getChildList(
			Map<String, String> rootNodeMap,
			List<Map<String, String>> allNodeList) {

		List<Map<String, String>> nodeMapList = new ArrayList<Map<String, String>>();
		for (Map<String, String> nodeMap : allNodeList) {
			if (nodeMap.get("parentId").equals(rootNodeMap.get("id"))) {
				nodeMapList.add(nodeMap);
			}
		}
		return nodeMapList;
	}

	/**
	 * 获得所有的菜单信息，这些信息保存到一个map的列表中
	 * @return
	 */
	public List<Map<String, String>> getAllMenuInfosByMap() {
		Collection<IMenuInfo> menuInfos = this.getAllMenuInfos();
		List<Map<String, String>> menus = new LinkedList<Map<String, String>>();
		if (menuInfos != null) {
			menus.addAll(this.getMenuInfosByMap());
		}
		return menus;
	}

	/**
	 * 获得与指定的用户及用户类型相关的菜单信息，这些信息保存到一个map的列表中
	 * @param userSerialno
	 * @param userType
	 * @return
	 */
/*	public List<Map<String, String>> getAllMenuInfosByMap(String userSerialno,
			String userType) {

		Collection<IMenuInfo> menuInfos = this.getAllMenuInfos();
		List<Map<String, String>> menus = new LinkedList<Map<String, String>>();
		if (menuInfos != null) {
			menus.addAll(this.getMenuInfosByMap(userSerialno, userType));
		}
		return menus;
	}*/

	/**
	 * 获得所有的根菜单信息
	 * @return
	 */
	public List<IMuneItemInfo> getAllRootMenuItemInfo() {
		List<IMuneItemInfo> itemList = new ArrayList<IMuneItemInfo>();
		Collection<IMenuInfo> menuInfoList = getAllMenuInfos();

		for (IMenuInfo menuInfo : menuInfoList) {
			List<IMuneItemInfo> itemInfoList = menuInfo.getRootMenuItemInfos();
			if (itemInfoList != null) {
				itemList.addAll(itemInfoList);
			}
		}
		Collections.sort(itemList);
		filterSameOrderItemOfList(itemList);
		return itemList;
	}

	/**
	 * 重新设置菜单项显示顺序。如果菜单项间的order属性是相同的，即显示的顺序一样，则会重新设置显示顺序。
	 * 
	 * @param itemList
	 * 
	 */
	public void filterSameOrderItemOfList(List<IMuneItemInfo> itemList) {

		if (itemList.size() <= 1) {
			return;
		}
		int maxOrder = Integer.parseInt(itemList.get(itemList.size() - 1)
				.getOrder()) + 1;

		for (int i = 0, j = 1; j <= itemList.size() - 1; i++, j++) {
			IMuneItemInfo preItem = itemList.get(i);
			IMuneItemInfo nextItem = itemList.get(j);
			int preOrder = Integer.parseInt(preItem.getOrder());
			int nextOrder = Integer.parseInt(nextItem.getOrder());
			if (preOrder == nextOrder) {
				preItem.setOrder(String.valueOf(maxOrder));
				maxOrder++;
			}
		}
		Collections.sort(itemList);
	}

	/**
	 * 获得指定根菜单的所有子菜单信息，并对子菜单排序
	 * @param id
	 * @return
	 */
	public List<IMuneItemInfo> getMenuItemsOfRootMenuItem(String id) {

		List<IMuneItemInfo> childMenuItemList = new ArrayList<IMuneItemInfo>();
		List<IMuneItemInfo> allMenuItemList = SaturnMenuManager.getInstance().allmemuItems;
		if (allMenuItemList != null) {
			for (IMuneItemInfo itemInfo : allMenuItemList) {
				if (itemInfo.getParentId().equals(id)) {
					childMenuItemList.add(itemInfo);
				}
			}
		}
		if (childMenuItemList != null) {
			Collections.sort(childMenuItemList);
			filterSameOrderItemOfList(childMenuItemList);
		}
		return childMenuItemList;
	}
	
	/**
	 * 获得所有的菜单项信息
	 * @return
	 */
	public List<IMuneItemInfo> getAllMenuItemInfos() {
		List<IMuneItemInfo> menuItemInfoList = new ArrayList<IMuneItemInfo>();
		Collection<IMenuInfo> menuInfoCollection = getAllMenuInfos();
		if (menuInfoCollection != null) {

			for (IMenuInfo menuInfo : menuInfoCollection) {
				List<IMuneItemInfo> partMenuItemList = menuInfo
						.getMenuItemInfos();

				if (partMenuItemList != null) {
					menuItemInfoList.addAll(partMenuItemList);
				}
			}
		}
		return menuItemInfoList;
	}
	private String getNodePath(IMuneItemInfo node) {
		String path = node.getPath();

		if (path == null || path.trim().equals("")) {
		return path;
		}

		String symbolicName = node.getMenuInfo().getBundleSymbolicName();

		if (path.endsWith(".action")) {
		if (path.indexOf("::") >= 0) {
		return path;
		}

		return "/" + symbolicName + "::" + path;
		} else {
		if (path.indexOf(symbolicName) >= 0) {
		return path;
		}

		return "/" + symbolicName + path;
		}
	}
//	private String getNodePath(IMuneItemInfo node) {
//		String path = node.getPath();
//		
//		if (path == null || path.trim().equals("")) {
//			return path;
//		}
//		
//		if (path.indexOf("::") >= 0) {
//			return path;
//		}
//		
//		String symbolicName = node.getMenuInfo().getBundleSymbolicName();
//		
//		if (path.endsWith(".action")) {
//			return "/" + symbolicName + "::" + path;
//		} else {
//			return "/" + symbolicName + "/" + path;
//		}
//		
//	}
}
